#include "Vault_t.h"

#include <memory>
#include <map>

#include "sgx_trts.h"
#include "EnclaveVault.h"
#include "../EnclaveWrap/EnclaveWrap.h"

std::map<std::string, std::shared_ptr<EnclaveVault>> g_vaults;

int initVault(const char *id)
{
	auto vault = std::shared_ptr<EnclaveVault>(new EnclaveVault(id));
    
    int return_code = vault->initEnclaveVault();

	g_vaults.insert(std::pair<std::string, std::shared_ptr<EnclaveVault>>(std::string(id), vault));

	return return_code;
}

int uninitVault(const char *id)
{
	g_vaults.erase(std::string(id));

	return 0;
}

int encrypt_size(const char *id, int buf_len)
{
	auto vault_id = std::string(id);
	if (g_vaults[vault_id] == nullptr)
	{
		return 0;
	}

	return g_vaults[vault_id]->encrypt_size(buf_len);
}

int encrypt(const char *id, const char *in_buf, int in_buf_len, char *out_buf, int out_buf_size)
{
	auto vault_id = std::string(id);
    if (g_vaults[vault_id] == nullptr)
    {
        return 0;
    }

    return g_vaults[vault_id]->encrypt(in_buf, in_buf_len, out_buf, out_buf_size);
}

int encryptex(const char *id, const char *in_buf, int in_buf_len, const int *value_lens, const int *value_types, int value_count, char *out_buf, int out_buf_size, int *out_value_lens)
{
	auto vault_id = std::string(id);
	if (g_vaults[vault_id] == nullptr)
	{
		return 0;
	}

	auto vault = g_vaults[vault_id];
	int in_buf_pos = 0;
	int out_buf_pos = 0;

	for (int i = 0; i < value_count; i++)
	{
		if (value_lens[i] == 0)
		{
			continue;
		}

		if (value_types[i] == 0)
		{
			int len = vault->encrypt(in_buf + in_buf_pos, value_lens[i], out_buf + out_buf_pos, out_buf_size - out_buf_pos);
			if (len == 0)
			{
				return 0;
			}
			out_value_lens[i] = len;
		}
		else 
		{
			out_value_lens[i] = value_lens[i];
			memcpy(out_buf + out_buf_pos, in_buf + in_buf_pos, value_lens[i]);
		}

		in_buf_pos += value_lens[i];
		out_buf_pos += out_value_lens[i];
	}

	return out_buf_pos;
}

int decrypt(const char *id, const char *in_buf, int in_buf_len, char *out_buf, int out_buf_size)
{
	auto vault_id = std::string(id);
	if (g_vaults[vault_id] == nullptr)
	{
		return 0;
	}

	return g_vaults[vault_id]->decrypt(in_buf, in_buf_len, out_buf, out_buf_size);
}

int public_key_encrypt(const char *id, const char *in_buf, int in_buf_len, char *out_buf, int out_buf_size)
{
	auto vault_id = std::string(id);
	if (g_vaults[vault_id] == nullptr)
	{
		return 0;
	}

	return g_vaults[vault_id]->public_key_encrypt(in_buf, in_buf_len, out_buf, out_buf_size);
}

int private_key_decrypt(const char *id, const char *in_buf, int in_buf_len, char *out_buf, int out_buf_size)
{
	auto vault_id = std::string(id);
	if (g_vaults[vault_id] == nullptr)
	{
		return 0;
	}

	return g_vaults[vault_id]->private_key_decrypt(in_buf, in_buf_len, out_buf, out_buf_size);
}

int private_key_encrypt(const char *id, const char *in_buf, int in_buf_len, char *out_buf, int out_buf_size)
{
	auto vault_id = std::string(id);
	if (g_vaults[vault_id] == nullptr)
	{
		return 0;
	}

	return g_vaults[vault_id]->private_key_encrypt(in_buf, in_buf_len, out_buf, out_buf_size);
}

int public_key_decrypt(const char *id, const char *in_buf, int in_buf_len, char *out_buf, int out_buf_size)
{
	auto vault_id = std::string(id);
	if (g_vaults[vault_id] == nullptr)
	{
		return 0;
	}

	return g_vaults[vault_id]->public_key_decrypt(in_buf, in_buf_len, out_buf, out_buf_size);
}

int sign(const char *id, const char *in_buf, int in_buf_len, char *out_buf, int out_buf_size)
{
	auto vault_id = std::string(id);
	if (g_vaults[vault_id] == nullptr)
	{
		return 0;
	}

	return g_vaults[vault_id]->sign(in_buf, in_buf_len, out_buf, out_buf_size);
}

int sha256_encrytp(const char *id, const char *in_buf, int in_buf_len, char *out_buf, int out_buf_size)
{
	auto vault_id = std::string(id);
	if (g_vaults[vault_id] == nullptr)
	{
		return 0;
	}

	return g_vaults[vault_id]->sha256(in_buf, in_buf_len, out_buf, out_buf_size);
}

int crypto_key(const char *id, char *key, int key_len)
{
	auto vault_id = std::string(id);
	if (g_vaults[vault_id] == nullptr)
	{
		return 0;
	}

	if (g_vaults[vault_id]->crypto_ == nullptr || g_vaults[vault_id]->crypto_->key_length() > key_len)
	{
		return 0;
	}

	memcpy(key, g_vaults[vault_id]->crypto_->key(), g_vaults[vault_id]->crypto_->key_length());

	return g_vaults[vault_id]->crypto_->key_length();
}